package de.slothsoft.commons.swing;

import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.swing.JTable;
import javax.swing.ListSelectionModel;

import de.slothsoft.commons.DisplayUtil;
import de.slothsoft.commons.IDisplayable;
import de.slothsoft.commons.swing.util.JTableUtil;

public class JCheckList<T extends IDisplayable> extends JTable {

	// TODO: make 0 and 1 to constants

	private static final long serialVersionUID = 1L;

	public JCheckList(T[] elements) {
		this(elements, false);
	}

	public JCheckList(T[] elements, boolean defaultValue) {
		setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		setShowGrid(false);
		addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				performMouseClick(e.getPoint());
			}
		});
		setModel(new CheckItemModel(elements));
		JTableUtil.setFixedColumnSize(getColumnModel().getColumn(0), 20);
		new SlothsoftTableCellRenderer();
		SlothsoftTableCellRenderer renderer = new SlothsoftTableCellRenderer();
		getColumnModel().getColumn(0).setCellRenderer(renderer);
		getColumnModel().getColumn(1).setCellRenderer(renderer);
	}

	protected void performMouseClick(Point point) {
		int column = columnAtPoint(point);

		if (column == 0) {
			int row = rowAtPoint(point);
			int modelRow = getRowSorter() == null ? row : getRowSorter()
					.convertRowIndexToModel(row);
			setSelectedItem(getCheckItemModel().getElement(modelRow));
		}
	}

	@SuppressWarnings("unchecked")
	public CheckItemModel getCheckItemModel() {
		return (CheckItemModel) super.getModel();
	}

	public void setSelectedItem(T item) {
		for (CheckItem<T> checkItem : getCheckItemModel().getList()) {
			if (checkItem.value == item) {
				setSelectedItem(checkItem);
				break;
			}
		}
	}

	public void setSelectedItem(CheckItem<T> item) {
		CheckItemModel model = getCheckItemModel();
		item.checked = !item.checked;
		int modelRow = model.getList().indexOf(item);
		model.fireTableRowsUpdated(modelRow, modelRow);
	}

	public void setSelectedItems(Collection<T> items) {
		if (items == null) {
			return;
		}
		for (T item : items) {
			for (CheckItem<T> checkItem : getCheckItemModel().getList()) {
				if (checkItem.value == item) {
					setSelectedItem(item);
				}
			}
		}
	}

	public Collection<T> getSelectedItems() {
		return getSelectedItems(new ArrayList<T>());
	}

	public Collection<T> getSelectedItems(Collection<T> collection) {
		collection.clear();
		for (CheckItem<T> checkItem : getCheckItemModel().getList()) {
			if (checkItem.checked) {
				collection.add(checkItem.value);
			}
		}
		return collection;
	}

	/*
	 * 
	 */

	public static class CheckItem<T> {
		T value;
		boolean checked;

		protected CheckItem(T value, boolean checked) {
			this.value = value;
			this.checked = checked;
		}

	}

	/*
	 * 
	 */

	class CheckItemModel extends AbstractListTableModel<CheckItem<T>> {

		private static final long serialVersionUID = 1L;

		public CheckItemModel(T[] array) {
			super(createList(array), new String[2]);
		}

		@Override
		protected Object getProperty(CheckItem<T> value, int column) {
			switch (column) {
			case 0:
				return Boolean.valueOf(value.checked);
			case 1:
				return DisplayUtil.toString(value.value);
			}
			return null;
		}
	}

	protected static <T> List<CheckItem<T>> createList(T[] array) {
		List<CheckItem<T>> list = new ArrayList<CheckItem<T>>();
		for (T a : array) {
			list.add(new CheckItem<T>(a, false));
		}
		return list;
	}

}
